#!/usr/bin/env python
# -*- coding: utf-8 -*-
import testlink
import openpyxl as op
from openpyxl.styles import Alignment
import time
import re
from enum import Enum

from PyQt5 import QtCore, QtGui, QtWidgets
import sys
import PyQt5.QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, qApp, QWidget, QFileDialog
from PyQt5.QtCore import Qt, QEvent, QObject
from functools import partial
import os
import time
from PyQt5.QtCore import QObject, pyqtSignal, QEventLoop, QTimer, QThread, QTime
from PyQt5.QtWidgets import QTextEdit

class Ui_MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(MainWindow)
        self.tlc = testlink.TestlinkAPIClient("http://192.168.0.201/testlink/lib/api/xmlrpc/v1/xmlrpc.php", "a695a58b5cde364a3a669bac4302054a")
        self.th = MyThread()
        self.th.signalForText.connect(self.outputWritten)               #线程的信号内容绑定到textBrowser
        sys.stdout = self.th  
    
    def outputWritten(self, text):                                      #输出到textBrowser
        cursor = self.textBrowser.textCursor()                          #获取指针对象
        # cursor.movePosition(QtGui.QTextCursor.End)                    #鼠标光标位置
        cursor.insertText(text)                                         #将外部数据放入指针内
        self.textBrowser.setTextCursor(cursor)                          #指针对象指向testbrowser
        # self.textBrowser.ensureCursorVisible()
        
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(539, 264)
        MainWindow.setMaximumSize(QtCore.QSize(539, 290))
        font = QtGui.QFont()
        font.setFamily("微软雅黑")
        font.setPointSize(12)
        MainWindow.setFont(font)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(340, 190, 161, 41))
        self.pushButton.setObjectName("pushButton")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(20, 60, 71, 31))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(40, 140, 41, 31))
        self.label_2.setObjectName("label_2")
        self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
        self.textBrowser.setGeometry(QtCore.QRect(260, 0, 271, 181))
        self.textBrowser.setObjectName("textBrowser")
        self.comboBox = QtWidgets.QComboBox(self.centralwidget)
        self.comboBox.setGeometry(QtCore.QRect(90, 60, 141, 31))
        self.comboBox.setObjectName("comboBox")
        self.comboBox_2 = QtWidgets.QComboBox(self.centralwidget)
        self.comboBox_2.setGeometry(QtCore.QRect(90, 140, 141, 31))
        self.comboBox_2.setObjectName("comboBox_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "自动生成excel"))
        self.pushButton.setText(_translate("MainWindow", "开始桌面生成excel"))
        self.label.setText(_translate("MainWindow", "工程版本"))
        self.label_2.setText(_translate("MainWindow", "IP名"))
        self.textBrowser.append("选择好测试计划启动即可~")


        # self.pushButton.clicked.connect(self.get_textcase)
        self.pushButton.clicked.connect(self.start_gogogo)
        self.comboBox.currentIndexChanged.connect(self.testplan_get)

    def get_textcase(self):
        self.comboBox.clear()
        test_url= "http://192.168.0.201/testlink/lib/api/xmlrpc/v1/xmlrpc.php"
        test_key = "a695a58b5cde364a3a669bac4302054a"
        do_link = TestLink(test_url, test_key)
        list_1 = do_link.available_projects
        for i in list_1:
            # print(i['name'])
            self.comboBox.addItems(i['name'].split(','))
        
    
    def testplan_get(self):
        self.comboBox_2.clear()
        tlc = testlink.TestlinkAPIClient("http://192.168.0.201/testlink/lib/api/xmlrpc/v1/xmlrpc.php", "a695a58b5cde364a3a669bac4302054a")
        projects = tlc.getProjects()
        d = []
        m = []
        for i in projects:
            c = ''.join(i['id'])
            e = ''.join(i['name'])
            d.append(c)
            m.append(e)
            n = dict(zip(m,d)) 
        # print(n)                                                            #一堆列表数字
        # for k,v in n.items():
        ip = [v for k , v in n.items() if k == self.comboBox.currentText()]
        # print(self.comboBox.currentText())
        ip = ''.join(ip)
        ip = int(ip)
        # print(ips)
        # print(type(ip))
        # print(type(d))
        # print(ip)
        # print(d)
        ip_name = tlc.getFirstLevelTestSuitesForTestProject(ip)
        # print(ip_name)
        for item in ip_name:
            # print(item)
            self.comboBox_2.addItems(item['name'].split(','))
            # print(item['name'])
            # print(type(item['name']))
            # print(item['name'].split(','))
            # print(type(item['name'].split(',')))


    def start_gogogo(self):
        self.textBrowser.clear()
        self.th.start() 

class TESTLINK_CASE_TEST(Enum):
    AUTO_TEST = '2'
    MANUAL_TEST = '1'

class TESTLINK_CASE_ACTIVE(Enum):
    ACTIVE = '1'
    INACTIVE = '0'


def data_from_testlink(data):
    """
    用于处理从testlink中获取的数据进行处理
    :param data: 传入的数据
    :return: 返回数据为处理后的数据
    """
    # return data
    data = data.replace('\r', '')
    data = data.replace('\t', '')
    data = data.replace('\n', '')
    data = data.replace('&nbsp;', ' ')  # 替换空格
    data = data.replace('&rsquo;', '"')  # 转换中文单引号 ’为英文的 "
    data = data.replace('&lsquo;', '"')  # 转换中文单引号‘ 为英文的 "
    data = data.replace('&ldquo;', '"')  # 转换中文双引号“ 为英文的 "
    data = data.replace('&rdquo;', '"')  # 转换中文双引号 ” 为英文的 "
    data = data.replace('：', ":")  # 转换中文的冒号 ：为英文的冒号 :
    data = data.replace('，', ',')  # 转换中文的逗号 ，为英文的逗号 ,
    data = data.replace('&quot;', '\"')  # 转换 &quot; 为双引号
    data = data.replace('&#39;', '\'')  # 转换 &#39;  为单引号
    data = data.replace('｛', '{')  # 转换中文｛ 为英文的 {
    data = data.replace('｝', '}')  # 转换中文 ｝ 为英文的 }
    data = data.replace('&lt;', '<')  # 转换 &lt; 为 <
    data = data.replace('&gt;', '>')  # 转换 &gt为 >
    data = data.replace('&amp;', '&')
    data = data.replace('【', '[')
    data = data.replace('】', ']')
    # 查找类似这类内容 </pre>、</div> 并替换为空
    result_list = re.findall('</.?>', data)
    if result_list:
        for item in result_list:
            data = data.replace(item, '')
    # 查找类似这类内容 <pre style="background-color:#ffffff;color:#000000;font-family:'宋体';font-size:12pt;">  并替换为空
    result_list = re.findall('<.?[^<]*>', data)
    if result_list:
        for item in result_list:
            data = data.replace(item, '')

    data = data.lstrip()

    return data

class MyThread(QThread):
    signalForText = pyqtSignal(str)                                     #信号数据绑定pyqtSignal

    def write(self, text):                                              #发送文本
        self.signalForText.emit(str(text)) 

    def __init__(self, Data = None ,parent=None):                       #继承QT线程函数
        super(MyThread, self).__init__(parent)

    def run(self):
            print(time.asctime(time.localtime((time.time()))))
            test_url= "http://192.168.0.201/testlink/lib/api/xmlrpc/v1/xmlrpc.php"
            test_key = "a695a58b5cde364a3a669bac4302054a"
            test_project = ui.comboBox.currentText()
            do_link = TestLink(test_url, test_key)
            print(do_link.set_cur_project(test_project))
            wb = op.Workbook()
            ws = wb.worksheets[0]
            align = Alignment(horizontal='center', vertical='center',wrapText=True) #wrapText 自动换行
            ws.title = test_project
            ws.append(['suite1','suite2','caseid','casename','summary','preconditions','state','step_number','action','expected_results','execution_type'])
            c_suite1 = 1
            c_suite2 = 2
            c_caseid = 3
            c_casename = 4
            c_summary = 5
            c_preconditions = 6
            c_state = 7
            c_case_execution_type = 8
            row = 2
            column = 0
            starttime = time.time()
            for fl_suite in do_link.query_first_level_testsuits_for_project():
                if ui.comboBox_2.currentText() != '':
                    if fl_suite['name'] != ui.comboBox_2.currentText():
                        continue
                print('f-s: ',fl_suite,'------------')
                ws = wb.create_sheet(fl_suite['name'])
                ws.append(['suite1', 'suite2', 'caseid','casename', 'summary', 'preconditions', 'active','case_execution_type', 'step_number', 'action',
                        'expected_results', 'execution_type','author_login','status'])
                ws.column_dimensions['A'].width = 10
                ws.column_dimensions['B'].width = 10
                ws.column_dimensions['C'].width = 10
                ws.column_dimensions['D'].width = 10
                ws.column_dimensions['E'].width = 10
                ws.column_dimensions['F'].width = 40
                ws.column_dimensions['G'].width = 8
                ws.column_dimensions['H'].width = 10
                ws.column_dimensions['I'].width = 10
                ws.column_dimensions['J'].width = 50
                ws.column_dimensions['K'].width = 50
                ws.column_dimensions['L'].width = 10
                ws.column_dimensions['H'].width = 10
                ws.column_dimensions['I'].width = 10

                row = 2
                #------new sheet-----
                ws[row][0].value=fl_suite['name']
                r_start1=row
                for sl_suite in do_link.query_second_level_testsuits_for_project(fl_suite):
                    # print('f: ', fl_suite)
                    print('s-s: ', sl_suite)
                    ws[row][1].value = sl_suite['name']
                    do_link.get_testcases_for_suite(sl_suite['id'])
                    # print(do_link.get_testcases_for_suite(sl_suite['id']))
                    r_start2 = row
                    if do_link.current_case == []: #防止suite下无case导致错行
                        row+=1
                    for c_case in do_link.current_case:
                        case = do_link.query_testcase(c_case['id'])[0]  #query_testcase 返回的是只有一个元素的列表，所以用[0]来提取里面的元素（字典）
                        # print('id',case['id'])
                        # print('casename',c_case['name'])
                        ws[row][2].value=c_case['external_id']
                        # print('summary',case['summary'])
                        ws[row][3].value = case['name']
                        # ws[row][4].value = data_from_testlink(case['summary'])# .replace('<p>','').replace('</p>','')
                        ws[row][4].value = case['summary'] # .replace('<p>','').replace('</p>','')
                        # ws[row][5].value = data_from_testlink(case['preconditions'])#.replace('<p>','').replace('</p>','')
                        ws[row][5].value = case['preconditions'] #.replace('<p>','').replace('</p>','')
                        # print('active',case['active'])
                        ws[row][6].value = 'active' if case['active'] == '1' else 'inactive'
                        # print(case['status'])
                        ws[row][7].value = 'auto' if case['execution_type'] == '2' else 'manual'
                        ws[row][12].value = case['author_login']
                        ws[row][13].value = case['status']  #草稿-1  待评审-2 评审中-3 重做-4 废弃-5 Future-6 终稿-7
                        r_start3 = row
                        r_end3 = row
                        if not case['steps'] :  #防止某些case中没有步骤导致行数异常
                            row += 1
                            r_end3 = row - 1
                        for step in case['steps']:
                            # print('step_number: {0},execution_type:{1}'.format(step['step_number'],step['execution_type']))
                            ws[row][8].value = step['step_number']
                            # print('actions',step['actions'])
                            if step['actions'].count(">") > 2:
                                ws[row][9].value = step['actions']  # .replace('<p>','').replace('</p>','')
                            else:
                                ws[row][9].value = data_from_testlink(step['actions'])#.replace('<p>','').replace('</p>','')
                            # print('expected_results',step['expected_results'])
                            if step['expected_results'].count(">") > 2:
                                ws[row][10].value = step['expected_results']  # .replace('<p>','').replace('</p>','')
                            else:
                                ws[row][10].value = data_from_testlink(step['expected_results'])#.replace('<p>','').replace('</p>','')

                            ws[row][11].value = 'auto' if step['execution_type'] == '2' else 'manual'
                            row+=1
                            r_end3 = row - 1

                        for i in range(3,9):
                            ws.merge_cells(start_row=r_start3, end_row=r_end3, start_column=i, end_column=i)
                            ws[r_start3][i-1].alignment = align  # 设定合并单元格的样式
                        # break
                    r_end2=row-1
                    ws.merge_cells(start_row=r_start2, end_row=r_end2, start_column=2, end_column=2)
                    ws[r_start2][1].alignment = align  # 设定列的样式
                    # break
                r_end1=row-1
                ws.merge_cells(start_row=r_start1, end_row=r_end1, start_column=1, end_column=1)
                ws[r_start1][0].alignment = align  # 设定列的样式
                # break
                row+=1
                # if row>1000:
                #     break
            wb.save('C:/Users/dell/Desktop/' + ui.comboBox_2.currentText() + '.xlsx')
            wb.close()
            endtime = time.time()
            print('---------------------------------')
            print('-------------finish!-------------')
            print('---------------------------------')
            # print(time.asctime(time.localtime((time.time()))))
            # print(endtime-starttime)

class TestLink:
    """
    用于初始化testlink连接，定义相应函数
    :param url: testlink url
    :param key: 用户 api接口密钥
    :return:
    """
    def __init__(self, url, key):
        self.current_project = None
        self.current_suite = []
        self.current_case = []
        self.first_level_suites = []
        self.second_level_suites = []

        self.available_projects = []
        self.available_suite = None
        self.available_plan = None

        self.tlc = testlink.TestlinkAPIClient(url, key)

        projects = self.tlc.getProjects()
        for prj in projects:
            if prj['active'] == TESTLINK_CASE_ACTIVE.ACTIVE.value:
                project = {}
                project['name'] = prj['name']
                project['id'] = prj['id']
                self.available_projects.append(project);
        # print(self.available_projects)

    def query_available_projects(self):
        """
            返回当前可用的project
            :return:当前可用的project
        """
        print(self.available_projects)
        return self.available_projects

    def set_cur_project(self, project_name):
        """
        寻找指定的project，并返回project对应的id
        :param project_name: 指定的project名称
        :return:指定的project对应的id
        """
        self.current_project = None
        self.available_plan = []
        self.available_suite = []

        find_project = False
        for prj in self.available_projects:
            if prj['name'] == project_name:
                prj_id = prj['id']
                find_project = True
                break

        if find_project:
            self.current_project = prj_id

        return self.current_project


    def query_testcase(self, caseid):
        """
        根据caseid获取case信息
        :param caseid: 指定的caseid
        :return:case步骤等信息
        """
        return self.tlc.getTestCase(caseid)

    def query_first_level_testsuits_for_project(self):
        """
        获取当前project下的一级目录testsuits
        :return:当前project下的一级目录testsuits的id列表
        """
        self.first_level_suites = []

        fl_suites = self.tlc.getFirstLevelTestSuitesForTestProject(self.current_project)
        # print('------------')
        # print(self.current_project)
        # print(fl_suites)
        for suite in fl_suites:
            cur_suite={}
            cur_suite['name']=suite['name']
            cur_suite['id']=suite['id']
            self.first_level_suites.append(cur_suite)
        return self.first_level_suites

    def query_second_level_testsuits_for_project(self,fl_suites):
        """
        获取一级目录suit下的二级目录testsuits
        :param fl_suites: 一级目录的testsuite
        :return:当前suit下的下一级目录testsuits的id列表
        """
        self.second_level_suites = []
        sl_suites = self.tlc.getTestSuitesForTestSuite(fl_suites['id'])
        if sl_suites == []:    #若没有二级目录，继承一级目录
            self.second_level_suites.append(fl_suites)
            return self.second_level_suites
        for suite in sl_suites.values():
            cur_suite={}
            cur_suite['name']=suite['name']
            cur_suite['id']=suite['id']
            self.second_level_suites.append(cur_suite)
        return self.second_level_suites

    def get_testcases_for_suite(self, suite_id):
        """
        获取suite下的testcase信息
        :param suite_id: suite id
        :return:当前suit下的下一级目录testsuits的id列表
        """
        self.current_case = []
        suite_case = self.tlc.getTestCasesForTestSuite(suite_id, 'deep','details')
        for case in suite_case:
            cur_case = {}
            cur_case['id'] = case['id']
            cur_case['external_id'] = case['external_id']
            self.current_case.append(cur_case)
        return self.current_case


if __name__ == '__main__':
    app = QApplication(sys.argv)
    MainWindow = QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    ui.get_textcase()

    MainWindow.show()
    sys.exit(app.exec_())


